#include "objLoader.h"

void objModel::display(float xPos, float yPos, float zPos, float xRot, float yRot, float zRot, std::string matName)
{
	float l[3];
	glPushMatrix();
	glScaled(.05,.05,.05); //CHANGE TO SCALE VARIABLES
	glTranslated(xPos, yPos, zPos);

	glRotatef(xRot, 1.0, 0.0, 0.0); //rotate on the x axis
	glRotatef(yRot, 0.0, 1.0, 0.0); //rotate on the y axis
	glRotatef(zRot, 0.0, 0.0, 1.0); //rotate on the z axis

	glEnable( GL_TEXTURE_2D ); //?
	glBegin(GL_TRIANGLES);
	

	int vertScale = 3;

	for(int y=0; y<vMatgrp.size(); y++)
	{
		if(vMatgrp[y]->matName.compare(matName) == 0 || matName == "")
		{
			for(int x=0; x<vMatgrp[y]->numFaces; x++)
			{
				l[0] = aVertexNormals[vMatgrp[y]->aFaces[x].vX-1].x;
				l[1] = aVertexNormals[vMatgrp[y]->aFaces[x].vX-1].y;
				l[2] = aVertexNormals[vMatgrp[y]->aFaces[x].vX-1].z;
				glNormal3fv(l);
				glTexCoord2f(aTextureVertices[vMatgrp[y]->aFaces[x].vtX-1].x, aTextureVertices[vMatgrp[y]->aFaces[x].vtX-1].y);
				glVertex3f( aVertices[vMatgrp[y]->aFaces[x].vX-1].x, aVertices[vMatgrp[y]->aFaces[x].vX-1].y, aVertices[vMatgrp[y]->aFaces[x].vX-1].z);

				l[0] = aVertexNormals[vMatgrp[y]->aFaces[x].vY-1].x;
				l[1] = aVertexNormals[vMatgrp[y]->aFaces[x].vY-1].y;
				l[2] = aVertexNormals[vMatgrp[y]->aFaces[x].vY-1].z;
				glNormal3fv(l);
				glTexCoord2f(aTextureVertices[vMatgrp[y]->aFaces[x].vtY-1].x, aTextureVertices[vMatgrp[y]->aFaces[x].vtY-1].y);
				glVertex3f( aVertices[vMatgrp[y]->aFaces[x].vY-1].x, aVertices[vMatgrp[y]->aFaces[x].vY-1].y, aVertices[vMatgrp[y]->aFaces[x].vY-1].z);

				l[0] = aVertexNormals[vMatgrp[y]->aFaces[x].vZ-1].x;
				l[1] = aVertexNormals[vMatgrp[y]->aFaces[x].vZ-1].y;
				l[2] = aVertexNormals[vMatgrp[y]->aFaces[x].vZ-1].z;
				glNormal3fv(l);
				glTexCoord2f(aTextureVertices[vMatgrp[y]->aFaces[x].vtZ-1].x, aTextureVertices[vMatgrp[y]->aFaces[x].vtZ-1].y);
				glVertex3f( aVertices[vMatgrp[y]->aFaces[x].vZ-1].x, aVertices[vMatgrp[y]->aFaces[x].vZ-1].y, aVertices[vMatgrp[y]->aFaces[x].vZ-1].z);
			}
		}
	}
	glEnd();

	glPopMatrix();
}

float toFloat(std::string f)
{
	float fl=0;
	std::stringstream ss;
	ss << f;
	ss >> fl;
	return fl;

}
objModel::objModel()
{
}

objModel::~objModel()
{
	delete [] aVertices;
	delete [] aTextureVertices;
	delete [] aVertexNormals;
	for (std::vector<matGroup*>::iterator it = vMatgrp.begin(); it!=vMatgrp.end(); ++it)
	{
		delete [] (*it)->aFaces;
		it = vMatgrp.erase(it);
	}
//FIX
}
bool parceFaceSub(face arrayIn[], std::string s, int pos, char c)
{
	//Should be 23/43/5 or something
	std::string s1 = "";
	std::string s2 = "";
	std::string s3 = "";
	int x=0;
	while(s[x] != '/')
	{
		s1+=s[x];
		x++;
	}
	x++;
	while(s[x] != '/')
	{
		s2+=s[x];
		x++;
	}
	x++;
	while(x != s.length())
	{
		s3+=s[x];
		x++;
	}
	if(c == 'x')
	{
		arrayIn[pos].vX = toFloat(s1);
		arrayIn[pos].vtX = toFloat(s2);
		arrayIn[pos].vnX = toFloat(s3);
	}
	if(c == 'y')
	{
		arrayIn[pos].vY = toFloat(s1);
		arrayIn[pos].vtY = toFloat(s2);
		arrayIn[pos].vnY = toFloat(s3);
	}
	if(c == 'z')
	{
		arrayIn[pos].vZ = toFloat(s1);
		arrayIn[pos].vtZ = toFloat(s2);
		arrayIn[pos].vnZ = toFloat(s3);
	}
	return true;
}
bool parseFaceList(face arrayIn[], std::string s, int pos)
{
	bool start=false;

	std::string xS = "";
	std::string yS = "";
	std::string zS = "";
	for(int x=0; x<s.length(); x++)
	{
		if (x+1 < s.length())
		{
			if (s[x]==' ' && s[x+1]!=' ' && start==false) //if there is a space before a non space we are there.
			{
				start=true;
				x++; //move cursor to the first element of the first number.
			}
		}
		if(start == true)
		{
			while(s[x] != ' ') //Yeah I'm lazy, so what? Wanna fight about it?
			{
				xS += s[x];
				x++;
			}
			x++;
			while(s[x] != ' ')
			{
				yS += s[x];
				x++;
			}
			x++;
			while(x != s.length())
			{
				zS += s[x];
				x++;
			}
			parceFaceSub(arrayIn, xS, pos, 'x');
			parceFaceSub(arrayIn, yS, pos, 'y');
			parceFaceSub(arrayIn, zS, pos, 'z');
			return true;
		}
	}
	return false;
}
bool parseVecList(vec arrayIn[], std::string s, int pos)
{
	bool start=false;

	std::string xS = "";
	std::string yS = "";
	std::string zS = "";
	for(int x=0; x<s.length(); x++)
	{
		if (x+1 < s.length())
		{
			if (s[x]==' ' && s[x+1]!=' ' && start==false) //if there is a space before a non space we are there.
			{
				start=true;
				x++; //move cursor to the first element of the first number.
			}
		}
		if(start == true)
		{
			while(s[x] != ' ') //Yeah I'm lazy, so what? Wanna fight about it?
			{
				xS += s[x];
				x++;
			}
			x++;
			while(s[x] != ' ')
			{
				yS += s[x];
				x++;
			}
			x++;
			while(x != s.length())
			{
				zS += s[x];
				x++;
			}
			//std::cout << xS << " ";
			//std::cout << yS << " ";
			//std::cout << zS << "\n";
			arrayIn[pos].x = toFloat(xS);
			arrayIn[pos].y = toFloat(yS);
			arrayIn[pos].z = toFloat(zS);
			return true;
		}
	}
	return false;
}
std::string parseMatName(std::string line)
{
	return line.substr(7); //return [name] in  usemtl [name]
}
void objModel::parseFace(std::string in)
{
	numFaces++; //global num faces
	bool exists= false;
	//check to see if the currentMat already exists, if it does add 1 to the face.
	for(int x=0; x<vMatgrp.size(); x++)
	{
		if(vMatgrp[x]->matName.compare(in) == 0)
		{
			exists = true;
			vMatgrp[x]->numFaces++;
		}
	}
	if (!exists) //add a new material group.
	{
		matGroup* m = new matGroup;
		m->matName = in;
		m->numFaces = 1;
		m->aFPos = 0;
		vMatgrp.push_back(m);
	}
}
int objModel::numMatGroups()
{
	return vMatgrp.size();
}
std::string objModel::getMatName(int matGroup)
{
	return vMatgrp[matGroup]->matName;
}
bool objModel::load(const char* path) //this method wastes CPU as opposed to ram.
{
	std::string line = "";
	char c1,c2;
	numVertices=0;
	numTextureVertices=0;
	numVertexNormals=0;
	numFaces=0;
	//numMaterials=0; //ONLY CHECK FOR UNIQUE ONES. get num faces for each material as well.
	std::string currentMat = "default";

	std::ifstream fileIn(path);
	if (fileIn.is_open())
	{
		while (getline (fileIn,line) ) //Scan through the file first and get size of data arrays. 
		{

			if (line.length() > 3)
			{
				c1 = line[0];
				c2 = line[1];
				if(c1 == 'v' && c2 == ' ' || c1 == 'V' && c2 == ' ') numVertices++;
				if(c1 == 'v' && c2 == 't' || c1 == 'V' && c2 == 'T') numTextureVertices++;
				if(c1 == 'v' && c2 == 'n' || c1 == 'V' && c2 == 'N') numVertexNormals++;
				if(c1 == 'f' && c2 == ' ' || c1 == 'F' && c2 == ' ') parseFace(currentMat);//numFaces++;
				if(c1 == 'u' && c2 == 's') currentMat = parseMatName(line);
			}
		}
		aVertices = new vec[numVertices];
		aTextureVertices = new vec[numTextureVertices];
		aVertexNormals = new vec[numVertexNormals];


		//setup mat groups
		for(int x=0; x<vMatgrp.size(); x++)
		{
			vMatgrp[x]->aFaces = new face[vMatgrp[x]->numFaces];
		}

		int aVPos=0;
		int aTVPos=0;
		int aVNPos=0;


		//fileIn.seekg(std::ios::beg); //go back to beginning of file. DOESNT WORK FOR SOME REASON
		//fileIn.clear(); //reset eof
		fileIn.close();
		std::ifstream fileIn2(path);
		while (getline (fileIn2,line) ) //Scan through the file and put data into arrays
		{
			if (line.length() > 3)
			{
				c1 = line[0];
				c2 = line[1];
				if(c1 == 'v' && c2 == ' ' || c1 == 'V' && c2 == ' ')
				{ 
					parseVecList(aVertices, line, aVPos); 
					aVPos++; 
				}
				if(c1 == 'v' && c2 == 't' || c1 == 'V' && c2 == 'T')
				{
					parseVecList(aTextureVertices, line, aTVPos); 
					aTVPos++;
				}
				if(c1 == 'v' && c2 == 'n' || c1 == 'V' && c2 == 'N')
				{
					parseVecList(aVertexNormals, line, aVNPos);
					aVNPos++;
				}
				if(c1 == 'f' && c2 == ' ' || c1 == 'F' && c2 == ' ')
				{
					for(int x=0; x<vMatgrp.size(); x++)
					{
						if(vMatgrp[x]->matName.compare(currentMat) == 0)
						{
							parseFaceList(vMatgrp[x]->aFaces, line, vMatgrp[x]->aFPos);
							vMatgrp[x]->aFPos++;
						}
					}
				}
				if(c1 == 'u' && c2 == 's') currentMat = parseMatName(line);
			}
		}
		//std::cout << aVertexNormals[3].z << "\n\n";

		fileIn2.close();
		//std::cout << "Model loaded " << path << "\n";
		return true;
	}else{
		std::cout << "Unable to load " << path << "\n";
	}

	return false;
}